// server.js
const express = require('express');
const http = require('http');
const path = require('path');
const reload = require('reload'); // 仅在非生产环境启用
const bodyParser = require('body-parser');
const logger = require('morgan');
const cors = require('cors');
const { createProxyMiddleware } = require('http-proxy-middleware');

const app = express();

/* ======================= 基础配置（支持环境变量） ======================= */
const PORT = parseInt(process.env.PORT || '8000', 10);
const isProd = process.env.NODE_ENV === 'production';

// 统一的 API 前缀，前端一律请求相对路径：/api/**
const API_PREFIX = process.env.API_PREFIX || '/api';

// 通过环境变量切换上游地址，实现“一次打包，多环境运行”
const TARGET = process.env.UPSTREAM || 'http://192.168.1.81:8000';
const TARGET_HOST_HEADER = process.env.UPSTREAM_HOST || ''; // 如需指定 Host：api.example.com

const CLIENT_TIMEOUT_MS = parseInt(process.env.CLIENT_TIMEOUT_MS || '60000', 10);
const UPSTREAM_TIMEOUT_MS = parseInt(process.env.UPSTREAM_TIMEOUT_MS || '60000', 10);

// 允许的 CORS 源，多个用逗号分隔；不设置则放通（同域部署亦可直接不配 CORS）
const ALLOW_ORIGINS = (process.env.CORS_ORIGINS || '')
  .split(',')
  .map(s => s.trim())
  .filter(Boolean);

/* ======================= 应用级设置 ======================= */
app.set('port', PORT);
app.set('trust proxy', 1);

/* --------- keep-alive 代理连接，避免频繁握手 --------- */
const keepAliveAgent = new http.Agent({
  keepAlive: true,
  keepAliveMsecs: 10_000,
  maxSockets: 128,
  maxFreeSockets: 32,
  timeout: 0 // 不在 socket 层强杀，让 proxyTimeout 控制
});

/* ----------------------- 安全的代理错误处理器 ----------------------- */
function safeProxyOnError(err, req, res) {
  console.error(
    '[ProxyError]',
    err?.code || 'UNKNOWN',
    err?.message || 'Proxy Error',
    req.method,
    req.originalUrl
  );

  if (res.headersSent || res.writableEnded) {
    try { res.end(); } catch (_) { }
    return;
  }
  if (req.aborted) return;

  const transient = new Set(['ECONNREFUSED', 'ENOTFOUND', 'EAI_AGAIN', 'ETIMEDOUT', 'ECONNRESET']);
  const status = transient.has(err?.code) ? 502 : 500;

  res.statusCode = status;
  res.setHeader('Content-Type', 'application/json; charset=utf-8');
  res.setHeader('Cache-Control', 'no-store');
  res.end(JSON.stringify({
    error: 'proxy_error',
    code: err?.code || 'UNKNOWN',
    message: err?.message || 'Proxy Error'
  }));
}
/* ------------------------------------------------------------------ */

/* ======================= 轻量中间件（不会消费请求体） ======================= */

// CORS：默认允许所有来源；若配置了 CORS_ORIGINS 则只允许名单内
const corsOptions = {
  origin(origin, cb) {
    if (!origin) return cb(null, true); // 非浏览器或同源
    if (ALLOW_ORIGINS.length === 0) return cb(null, true);
    const ok = ALLOW_ORIGINS.includes(origin);
    cb(ok ? null : new Error('Not allowed by CORS'), ok);
  },
  credentials: true
};
app.use(cors(corsOptions));

app.use(logger(isProd ? 'combined' : 'dev'));

/* =========== 预处理 API 请求头（在真正的代理前） =========== */
app.use(API_PREFIX, (req, _res, next) => {
  // 某些客户端会自动加 Expect，部分后端实现不支持，直接会 RST
  if (req.headers['expect']) delete req.headers['expect'];

  // 有些库会把 connection 设成 'upgrade'（非 WS 请求却升级），上游会直接挂
  if (req.headers['connection'] && /upgrade/i.test(req.headers['connection'])) {
    delete req.headers['connection'];
  }

  // 如果你需要把原始 Host 透传给上游（虚拟主机）
  if (TARGET_HOST_HEADER) {
    req.headers['host'] = TARGET_HOST_HEADER;
  }

  next();
});

/* ======================= 代理（放在 body-parser 之前） ======================= */
app.use(
  API_PREFIX,
  createProxyMiddleware({
    target: TARGET,
    changeOrigin: true,      // Host 改成上游；若设置了 TARGET_HOST_HEADER，会在 onProxyReq 再覆盖
    xfwd: true,              // 加 X-Forwarded-* 头
    agent: keepAliveAgent,   // 使用 keep-alive
    ws: false,               // 若没有 WS，可显式关闭
    pathRewrite: { [`^${API_PREFIX}`]: `${API_PREFIX}` },
    logLevel: isProd ? 'info' : 'debug',

    onProxyReq: (proxyReq, req, _res) => {
      // 便于调试
      console.log(`[Proxy] ${req.method} ${req.originalUrl} → ${TARGET}${req.url}`);

      // 如果上游要求特定 Host（虚拟主机），这里强制设置
      if (TARGET_HOST_HEADER) {
        proxyReq.setHeader('Host', TARGET_HOST_HEADER);
      }

      // 【防御性】一旦有人把 body-parser 移到前面导致 req 不再可读，这里重写请求体
      if (!req.readable && req.body && Object.keys(req.body).length) {
        const contentType = req.headers['content-type'] || '';
        let bodyData;

        if (contentType.includes('application/json')) {
          bodyData = JSON.stringify(req.body);
        } else if (contentType.includes('application/x-www-form-urlencoded')) {
          bodyData = new URLSearchParams(req.body).toString();
        }
        // multipart/form-data 不适合在这里重写（边界串需要原始流）

        if (bodyData) {
          proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
          // 不强制改 content-type，沿用客户端的
          proxyReq.write(bodyData);
        }
      }
    },

    onProxyRes: (proxyRes, req, _res) => {
      // 观察上游是否频繁返回 Connection: close（可能是它主动切 keep-alive）
      const conn = proxyRes.headers['connection'];
      if (conn && /close/i.test(String(conn))) {
        console.warn('[ProxyWarn] Upstream responded with Connection: close', req.method, req.originalUrl);
      }
    },

    onError: safeProxyOnError,

    // 超时：与客户端连接、与上游连接分别控制
    timeout: CLIENT_TIMEOUT_MS,       // 客户端到代理
    proxyTimeout: UPSTREAM_TIMEOUT_MS // 代理到上游
  })
);

/* ======================= 解析器等放在代理之后 ======================= */
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

/* ======================= 静态资源与页面 ======================= */
app.use('/public', express.static(path.join(__dirname, 'public')));
app.use('/pages', express.static(path.join(__dirname, 'pages')));

// 健康检查
app.get('/healthz', (_req, res) => {
  res.type('text/plain').send('ok');
});

// 根路径
app.get('/', (_req, res) => {
  res.sendFile(path.join(__dirname, 'index.html'));
});

// 单页应用路由回退（避免前端路由 404）——排除 API 前缀
app.get('*', (req, res, next) => {
  if (req.method !== 'GET') return next();
  if (req.path.startsWith(API_PREFIX)) return next();
  // 仅当请求看起来在要文档时才回退到 index.html
  if (req.headers.accept && req.headers.accept.includes('text/html')) {
    return res.sendFile(path.join(__dirname, 'index.html'));
  }
  next();
});

/* ======================= 全局错误兜底 ======================= */
app.use((err, _req, res, _next) => {
  if (res.headersSent) return;
  res.status(500).json({ error: 'internal_error', message: err?.message || 'Internal Error' });
});

/* ======================= 启动 ======================= */
const server = http.createServer(app);

const start = async () => {
  try {
    if (!isProd) {
      await reload(app); // 生产环境默认不启用 reload
    }
    server.listen(PORT, () => {
      console.log(`服务器运行在: http://localhost:${PORT}`);
      console.log(`API 前缀: ${API_PREFIX}`);
      console.log(`上游地址: ${TARGET}`, TARGET_HOST_HEADER ? `(Host: ${TARGET_HOST_HEADER})` : '');
      if (ALLOW_ORIGINS.length) {
        console.log('CORS 允许来源:', ALLOW_ORIGINS.join(', '));
      } else {
        console.log('CORS 允许所有来源（或同源）');
      }
      console.log(`环境: ${isProd ? 'production' : 'development'}`);
    });
  } catch (err) {
    console.error('启动失败:', err);
    process.exitCode = 1;
  }
};

start();
